package ar.edu.caece.compiler.error;

import static ar.edu.caece.compiler.grammar.AbstractTokenVisitorFactory.backToken;
import static ar.edu.caece.compiler.grammar.AbstractTokenVisitorFactory.currentSymbol;
import static ar.edu.caece.compiler.grammar.AbstractTokenVisitorFactory.nextSymbol;
import static ar.edu.caece.compiler.symbol.SymbolTable.EOF;
import static org.apache.commons.logging.LogFactory.getLog;

import java.util.ArrayList;
import java.util.List;

import org.apache.commons.logging.Log;

import ar.edu.caece.compiler.grammar.TokenRecognizer;
import ar.edu.caece.compiler.model.Grammar;
import ar.edu.caece.compiler.symbol.Symbol;
import ar.edu.caece.compiler.symbol.TerminalSymbol;

public class ErrorManager {
	
	private Log logger = getLog(ErrorManager.class);
	
	private static ErrorManager instance;
	
	private Grammar grammar;

	private List<String> errors;
	
	public static ErrorManager getInstance() {
		if(instance == null)
			instance = new ErrorManager();
		return instance;
	}
	
	private ErrorManager() {
		errors = new ArrayList<String>();
	}
	
	public void manage(TokenRecognizer recognizer, String expected) {
		try {
			
			List<TerminalSymbol> following = grammar.getFollowing(expected);

			for(Symbol symbol = currentSymbol(); !symbol.equals(EOF); symbol = nextSymbol()) 

				if(following.contains(symbol) || 
				  (symbol instanceof TerminalSymbol && ((TerminalSymbol)symbol).getSubtype().equals("IDENTIFIER") && following.contains(grammar.getSymbol("id")))) {
					backToken();
					break;
				}
			
			final String msg = "Syntax error on " + recognizer.getToken().getPos() + ". Expected: \"" + expected + "\" and received=\"" + recognizer.getToken().getSymbol() + "\""; 		
			logger.debug(msg);
			errors.add(msg);
			
		} catch (Exception e) {
			throw new RuntimeException("Error managing error, recognizer=" + recognizer + ", expected=" + expected, e);
		}
	}

	public void setGrammar(Grammar grammar) {
		this.grammar = grammar;
	}

	public List<String> getErrors() {
		return errors;
	}
}
